# 神经网络中有各种各样的层，我们将其实现为Python的类。通过这种模块化，可以像搭建乐高积木一样构建网络。本书在实现这些层时，
# 制定一下“代码规范”。
#     i) 所有的层都有forward()方法和backward()方法
#     ii) 所有层都有params和grads实例变量
# forward()方法和backward()方法分别对应正向传播和反向传播。其次，params使用列表保存权重和偏置等参数。grads以与params中的
# 参数对应形式，使用列表保存各个但是的梯度。

import numpy as np

class Sigmoid:
    def __init__(self):
        self.params,self.grads = [],[]
        self.out = None 

    def forward(self,x):
        out = 1/(1+np.exp(-x))
        self.out = out 
        return out 
    
    def backward(self,dout):
        dx = dout*(1-self.out)*self.out 
        return dx 
    
class Affine:
    def __init__(self,W,b):
        self.params = [W,b]
        # self.grads = [np.zeros_like(W),np.zeros_like(b)]

    def forward(self,x):
        W,b = self.params
        out = np.dot(x,W)+b
        return out 
    
class TwoLayerNet:
    def __init__(self,input_size,hidden_size,output_size):
        I,H,O = input_size,hidden_size,output_size

        # 初始化权重和偏置
        W1 = np.random.randn(I,H)
        b1 = np.random.randn(H)
        W2 = np.random.randn(H,O)
        b2 = np.random.randn(O)

        # 生成层
        self.layers = [
            Affine(W1,b1),
            Sigmoid(),
            Affine(W2,b2)
        ]

        # 将所有的权重整理到列表中
        self.params = []
        for layer in self.layers:
            self.params += layer.params
    
    def predict(self,x):
        for layer in self.layers:
            x = layer.forward(x)
        return x 
    
x = np.random.randn(10,2)
model = TwoLayerNet(2,4,3)
s = model.predict(x)
print(s.shape)